package model.environmentConfig;

import java.awt.*;

import javax.xml.bind.annotation.*;

import controller.ConnectionTester;

@XmlRootElement(name = "channel")
@XmlAccessorType(XmlAccessType.FIELD)
public class CommunicationChannel
{
	private static double CURSOR_RADIUS=3;
	public static final long TIME_OUT=6000;
	
	Long initiatorNode = null;
	Long listeningNode = null;
	
	Protocol transportProtocol = new Protocol("tcp");
	Protocol applicationProtocol = null;

	int initiatorPortRangeStart = -1;
	int initiatorPortRangeEnd = -1;
	int listenerPortRangeStart = -1;
	int listenerPortRangeEnd = -1;

	@XmlTransient
	ChannelState state=ChannelState.UNKNOWN;
	
	public CommunicationChannel(){
		
	}
	
	public CommunicationChannel(Long initNode, Long listNode, Protocol transport, Protocol application, int initRangeStart, int initRangeEnd, int listRangeStart, int listRangeEnd){
		this.initiatorNode = initNode;
		this.listeningNode = listNode;
		this.transportProtocol = transport;
		this.applicationProtocol = application;
		this.initiatorPortRangeStart = initRangeStart;
		this.initiatorPortRangeEnd = initRangeEnd;
		this.listenerPortRangeStart = listRangeStart;
		this.listenerPortRangeEnd= listRangeEnd;
	}
	
	public ChannelState getState(){
		return(state);
	}
	
	public void setState(ChannelState state){
		this.state=state;
	}
	
	public boolean overlaps(Point cursorLoc){
		EnvironmentConfiguration envConf=ConnectionTester.getEnvironmentConfig();
		
		if(envConf==null){
			return(false);
		}
		
		Point a=vectorize(envConf.getNodes().get(initiatorNode).getDisplayData().getCenter(), envConf.getNodes().get(listeningNode).getDisplayData().getCenter());
		Point b=vectorize(envConf.getNodes().get(initiatorNode).getDisplayData().getCenter(), cursorLoc);
		
		
		double abDist=envConf.getNodes().get(initiatorNode).getDisplayData().getCenter().distance(envConf.getNodes().get(listeningNode).getDisplayData().getCenter());
		double abDot=dotProduct(a, b);
		double someVar=abDot/dotProduct(a, a);
		double someOtherVar=abDot/Math.sqrt(dotProduct(a, a));
		double distance;
		
		if(someOtherVar<=0){
			distance=cursorLoc.distance(envConf.getNodes().get(initiatorNode).getDisplayData().getCenter());
		}
		else if(someOtherVar>=abDist){
			distance=cursorLoc.distance(envConf.getNodes().get(listeningNode).getDisplayData().getCenter());
		}
		else{
			Point c=vectorMulti(a, someVar);
			distance=b.distance(c);
		}
		
		return(distance<=CURSOR_RADIUS);
	}
	
	private static Point vectorize(Point origin, Point dest){
		Point result=new Point();
		
		result.setLocation(dest.getX()-origin.getX(), dest.getY()-origin.getY());
		return(result);
	}
	
	private static Point vectorMulti(Point a, double b){
		Point result=new Point();
		
		result.setLocation(a.getX()*b, a.getY()*b);
		return(result);
	}
	
	private static double dotProduct(Point a, Point b){
		double result;
		result=a.getX()*b.getX()+a.getY()*b.getY();
		return(result);
	}
	
	public Long getInitiatorNode()
	{
		return initiatorNode;
	}
	
	public void setInitiatorNode(Long setNode)
	{
		initiatorNode = setNode;
	}
	
	public Long getListeningNode()
	{
		return listeningNode;
	}
	
	public void setListeningNode(Long setNode)
	{
		listeningNode = setNode;
	}
	
	public Protocol getTransportProtocol()
	{
		return transportProtocol;
	}
	
	public void setTransportProtocol(Protocol setProtocol)
	{
		transportProtocol = setProtocol;
	}
	
	public Protocol getApplicationProtocol()
	{
		return applicationProtocol;
	}
	
	public void setApplicationProtocol(Protocol setProtocol)
	{
		applicationProtocol = setProtocol;
	}
	
	public int[] getInitiatorPortRange()
	{
		return(new int[]{initiatorPortRangeStart, initiatorPortRangeEnd});
	}
	
	public void setInitiatorPortRange(int rangeStart, int rangeEnd)
	{
		initiatorPortRangeStart = rangeStart;
		initiatorPortRangeEnd = rangeEnd;
	}
	
	public int[] getListenerPortRange()
	{
		return(new int[]{listenerPortRangeStart, listenerPortRangeEnd});
	}
	
	public void setListenerPortRange(int rangeStart, int rangeEnd)
	{
		listenerPortRangeStart = rangeStart;
		listenerPortRangeEnd = rangeEnd;
	}
	
	@Override
	public boolean equals(Object cc){
		if(!(cc instanceof CommunicationChannel)){
			return(false);
		}
		
		CommunicationChannel comcha=(CommunicationChannel)cc;
		if(this.initiatorNode!=null){
			if(comcha.getInitiatorNode()!=null){
				if(this.initiatorNode.compareTo(comcha.getInitiatorNode())!=0){
					return(false);
				}
			}
			else{
				return(false);
			}
		}
		
		if(this.listeningNode!=null){
			if(comcha.getListeningNode()!=null){
				if(this.listeningNode.compareTo(comcha.getListeningNode())!=0){
					return(false);
				}
			}
			else{
				return(false);
			}
		}
		
		if(this.initiatorPortRangeStart!=comcha.getInitiatorPortRange()[0]){
			return(false);
		}
		if(this.initiatorPortRangeEnd!=comcha.getInitiatorPortRange()[1]){
			return(false);
		}
		if(this.listenerPortRangeStart!=comcha.getListenerPortRange()[0]){
			return(false);
		}
		if(this.listenerPortRangeEnd!=comcha.getListenerPortRange()[1]){
			return(false);
		}

		
		if(this.transportProtocol!=null){
			if(comcha.getTransportProtocol()!=null){
				if(!(this.transportProtocol.equals(comcha.getTransportProtocol()))){
					return(false);
				}
			}
			else{
				return(false);
			}
		}
		if(this.applicationProtocol!=null){
			if(comcha.getApplicationProtocol()!=null){
				if(!(this.applicationProtocol.equals(comcha.getApplicationProtocol()))){
					return(false);
				}
			}
			else{
				return(false);
			}
		}
		
		return(true);
	}
}
